package dungeonDigger.entities;

import java.util.HashMap;
import java.util.Map;

import org.newdawn.slick.Animation;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.geom.ShapeRenderer;
import org.newdawn.slick.geom.Vector2f;

import dungeonDigger.Tools.Rectangle;
import dungeonDigger.Tools.References;
import dungeonDigger.collisions.QuadCollisionEngine;
import dungeonDigger.enums.CreatureStat;

public class Mob extends Agent {
	private SpriteSheet		sprites;
	private Animation		animation;
	private Vector2f		destination;
	private int				speed, intelligence = 1;
	private boolean			friendly			= false, exists = false, inited = false;
	private transient float	movementVariance	= 2f;
	private transient int	aggroRange			= 750;

	public Mob(String name) {
		this.setName( name );
	}

	public void init() {
		// Setup Animation
		animation.setSpeed( 0.3f );
		animation.restart();
		animation.setLooping( true );
		// Configure collision box based on graphic
		this.setCollisionBox( this.getPosition().x, this.getPosition().y, this.getAnimation().getCurrentFrame().getWidth(), this.getAnimation().getCurrentFrame().getHeight() );
		References.log.info( "Mob Inited" );
		inited = true;
	}

	@Override
	public void update(GameContainer c, int delta) {
		if( !exists() ) { return; }
		if( !inited ) {
			this.init();
		}
		int top = (int)( this.getPosition().y - this.getAggroRange() / 2 );
		int bottom = (int)( this.getPosition().y + this.getAggroRange() / 2 );
		int left = (int)( this.getPosition().x - this.getAggroRange() / 2 );
		int right = (int)( this.getPosition().x + this.getAggroRange() / 2 );
		// Check if the player is close enough to care
		if( References.myCharacter.getPosition().x > left && References.myCharacter.getPosition().x < right && References.myCharacter.getPosition().y > top
				&& References.myCharacter.getPosition().y < bottom ) {
			animation.update( delta );
			Vector2f movingAmount = MobAI.updateMovement( this );
			this.getPosition().add( movingAmount );
			if( this.getParentNode() == null || !this.getParentNode().contains( this ) || this.getParentNode().getChildren().size() > 0 ) {
				QuadCollisionEngine.relocate( this );
			}
			this.setCollisionBox( this.getPosition().x, this.getPosition().y, this.getAnimation().getCurrentFrame().getWidth(), this.getAnimation().getCurrentFrame().getHeight() );
		}
	}

	@Override
	public void render(GameContainer c, Graphics g) {
		if( !exists() ) { return; }
		animation.draw( this.getPosition().x, this.getPosition().y );
		if( References.DEBUG_MODE ) {
			ShapeRenderer.draw( this.getCollisionBox() );
		}
	}

	@Override
	public Rectangle getCollisionBox() {
		return new Rectangle( this.getPosition().x, this.getPosition().y, this.animation.getCurrentFrame().getWidth(), this.animation.getCurrentFrame().getHeight() );
	}

	@Override
	public Rectangle getDrawBox() {
		return this.getCollisionBox();
	}

	@Override
	public float getWidth() {
		return this.animation.getCurrentFrame().getWidth();
	}

	@Override
	public float getHeight() {
		return this.animation.getCurrentFrame().getHeight();
	}

	/** Spawns this mob at the position (in pixels)
	 * @param pos */
	public void spawn(Vector2f pos) {
		this.setPosition( pos.copy() );
		setExists( true );
		this.setCurrentHitPoints( this.getMaxHitPoints() );
	}

	public void die() {
		setExists( false );
	}

	public Mob clone() {
		Mob m = new Mob( this.name );
		m.setAnimation( this.animation.copy() );
		m.setFriendly( this.friendly );
		m.setMaxHitPoints( this.getMaxHitPoints() );
		m.setCurrentHitPoints( this.getMaxHitPoints() );
		m.setSpeed( this.speed );
		m.setSprites( this.sprites );
		// TODO: copy the rest.
		return m;
	}

	public SpriteSheet getSprites() {
		return sprites;
	}

	public void setSprites(SpriteSheet sprites) {
		this.sprites = sprites;
	}

	public Animation getAnimation() {
		return animation;
	}

	public void setAnimation(Animation animation) {
		this.animation = animation;
	}

	public Vector2f getDestination() {
		return destination;
	}

	public void setDestination(Vector2f destination) {
		this.destination = destination;
	}

	public int getSpeed() {
		return speed;
	}

	public void setSpeed(int speed) {
		this.speed = speed;
	}

	public boolean isFriendly() {
		return friendly;
	}

	public void setFriendly(boolean friendly) {
		this.friendly = friendly;
	}

	public boolean exists() {
		return exists;
	}

	public void setExists(boolean b) {
		this.exists = b;
	}

	public float getMovementVariance() {
		return movementVariance;
	}

	public void setMovementVariance(float movementVariance) {
		this.movementVariance = movementVariance;
	}

	public int getAggroRange() {
		return aggroRange;
	}

	public void setAggroRange(int aggroRange) {
		this.aggroRange = aggroRange;
	}

	public int getIntelligence() {
		return intelligence;
	}

	public void setIntelligence(int intelligence) {
		this.intelligence = intelligence;
	}

	// TODO: make stats into objects? return a map of the bonuses the zombie gets at that level of hunger, spd, str, etc.
	public Map<CreatureStat, Double> getBasicStats() {
		HashMap<CreatureStat, Double> stats = new HashMap<CreatureStat, Double>();
		return stats;
	}
}
